#####################################################################
# Product:      KnowledgeEngine (Plone Edition)
#
# File:         SelectionEditlet.py
#
# Copyright:    Copyright (c) 2004, Faulkner Technologies
#
# Author:       Brian Oliver
#
# Description:  This file defines the SelectionEditlet class, that is
#               used to generate single choice dropdowns for enumerated 
#               types
#
# See Also:     PropertyEditlet, PropertyRefleciton, 
#               PropertyDefinition, PropertyAccess 
#####################################################################

#####################################################################
## KnowledgeEngine Library Imports
from Products.KnowledgeEngine.Common import *
from Products.KnowledgeEngine.Core import *
from Products.KnowledgeEngine.Editlet import Editlet
from Products.KnowledgeEngine.PropertyDefinition import *
from Products.KnowledgeEngine.PropertyTypes import *
from Products.KnowledgeEngine.PropertyFormats import *
from Products.KnowledgeEngine.PropertyStructures import *

#####################################################################
## Zope Library Imports
# (none)
 
#####################################################################
## Python Library Imports
# (none)

#####################################################################
## SelectionEditlet Class Definition
class SelectionEditlet(Editlet):
    """
        An editlet for editing enumerated types
    """
    
    #---------------------------------------------------------------#

    def displayNameFor(self, value, possibleValues):
        """
            Returns the displayName for the specified value
            from the specified possible values.
            
            Returns "" iff there is no possibleValue
        """
        
        for (displayName, displayValue) in possibleValues:
            if displayValue == value:
                return displayName
               
        return ""
    
    #---------------------------------------------------------------#
    
    def isEditable(self, propertyDefinition, propertyAccess=None, value=None, isForConstructor=false, REQUEST=None, context=None):
        """
            Returns if the specified propertyDefinition can be
            edited by this editlet
        """

        return propertyDefinition.getStructure() == ps_ATOMIC and propertyDefinition.hasEnumeratedValues()
        
    #---------------------------------------------------------------#

    def generateEditorFor(self, propertyDefinition, propertyAccess=None, value=None, isForConstructor=false, REQUEST=None, context=None):
        """
            Returns a HTML editlet for the specified property.
        """

        #get the enumerated values [(DisplayName,Value)] from the property definition class (one must be provided)
        possibleValues = propertyDefinition.getEnumeratedValues(context)
        
        #ensure that we use a writeable editlet (if possible) if we are dealing with a mandatory property and we don't yet have a value
        if propertyDefinition.isMandatory() and propertyAccess is not None and (not hasattr(propertyAccess, propertyDefinition.getIdentity()) or getattr(propertyAccess, propertyDefinition.getIdentity()) is None):
            
            #we want an editletEVAP with the most permissions (which may not include write access)
            editletEVAP = propertyDefinition.getConstructorEVAP() | propertyDefinition.getPropertyEditorEVAP()
        
        else:
            #determine the type of editlet we need to produce based on editlet value access permission (EVAM)
            editletEVAP = iif(isForConstructor, propertyDefinition.getConstructorEVAP(), propertyDefinition.getPropertyEditorEVAP())
                
        #-----------------
        #no property editor is required
        if editletEVAP == evap_NONE:
            result = ""

        #-----------------
        #a read-only property editor is required
        elif editletEVAP == evap_READONLY:

            #get the value for the property
            if isForConstructor or propertyAccess is None:
                value = propertyDefinition.getDefaultValue()
            else:
                value = propertyAccess.getPropertyValue(propertyDefinition.getIdentity())
            
            #create the editor
            result = "<table border=1><tr><td>%s</td></tr></table>" % (self.displayNameFor(value,possibleValues),)
        
        #-----------------
        #a writeable property editor is required
        else: 
       
            #get the value for the property (if possible)
            if editletEVAP == evap_WRITEONLY:
                value = None
            else:
                if isForConstructor or propertyAccess is None:
                    value = propertyDefinition.getDefaultValue()
                else:
                    #get the value for the property
                    value = propertyAccess.getPropertyValue(propertyDefinition.getIdentity())
                
            #create the editor
            result = "<select id='%s' name='ke%s'>" % (propertyDefinition.getIdentity(),propertyDefinition.getIdentity(),)
            
            if propertyDefinition.hasArg('includeBlankOption') and propertyDefinition.getArg('includeBlankOption') == true:
                result += "<option value=\"\">Choose one:</option><option value=\"\">--</option>"
            
            for (displayName, displayValue) in possibleValues:
            
                if displayValue == value:
                    selected = " selected"
                else:
                    selected = ""                    

                #ensure our value doesn't get weirdly cast into a string!
                if propertyDefinition.getType() == pt_LONG or propertyDefinition.getType() == pt_INTEGER:
                    format = "%d"
                elif propertyDefinition.getType() == pt_FLOAT: 
                    format = "%f"
                else:          
                    format = "%s"
                    
                result += ("<option value='" + format + "'%s>%s</option>") % (displayValue, selected, displayName)
            
            result += "</select>"        
                                    
        return result
        
    #---------------------------------------------------------------#

    def containsPropertyValue(self, propertyDefinition, REQUEST):
        """
            Determines if the provided request contains
            a value for the specified propertyDefinition.
            
            This method is used (and is useful for) determining and
            updating the values of properties from property editors.
            
            All editlet implementations must override this method.            
        """
        
        return REQUEST.has_key("ke%s" % (propertyDefinition.getIdentity(),))
        
    #---------------------------------------------------------------#

    def updatePropertyWith(self, propertyDefinition, propertyAccess, REQUEST=None):
        """
            Attempts to update the specified property on the
            object implementing the PropertyAccess interface with the
            specified HTTP REQUEST.
        """

        #get the value from the request
        value = REQUEST["ke%s" % (propertyDefinition.getIdentity(),)]

        #ensure we have a value if it isMandatory
        propertyDefinition.verifyMandatoryValue(value)

        #appropriately cast the value into either a long, integer or float if necessary
        try:
            if propertyDefinition.getType() == pt_LONG:
                value = long(value)                
            elif propertyDefinition.getType() == pt_INTEGER:
                value = int(value)
            elif propertyDefinition.getType() == pt_FLOAT: 
                value = float(value)
            else:
                #no type casting required
                pass
                
        except ValueError:
            raise ValueError, ("A number was expected for the property '%s'" % propertyDefinition.getDisplayName())

        #set the value for the property from the REQUEST
        propertyAccess.setPropertyValue(propertyDefinition.getIdentity(), value)
        
    #---------------------------------------------------------------#

#####################################################################
## Class Initialisation

# Register Editlet Information with the Knowledge Engine
registerEditlet("SelectionEditlet", SelectionEditlet())

#####################################################################
